// --------------------------------------------------------------------------------------------------------------------
// <copyright file="OrderTrackingCell.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Framework.Forge
{
    #region Usings

    using System;
    using System.Collections.Generic;
    using System.Linq;

    using Org.OpenTrader.Framework.Forge.Enums;
    using Org.OpenTrader.Framework.Forge.Interfaces;

    #endregion

    /// <summary>
    /// The order tracking cell.
    /// </summary>
    [Serializable]
    public class OrderTrackingCell : IOrderTrackingCell
    {
        #region Constants and Fields

        /// <summary>
        /// The executions.
        /// </summary>
        private readonly IList<IExecution> executions = new List<IExecution>();

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="OrderTrackingCell"/> class.
        /// </summary>
        /// <param name="order">
        /// The order.
        /// </param>
        /// <param name="ordertracker">
        /// The ordertracker.
        /// </param>
        public OrderTrackingCell(IOrder order, IOrderTracker ordertracker)
        {
            this.Order = order;
            this.Created = true;
            this.CreateStamp = Timings.Now;
            this.Side = order.Way;
            this.Tracker = ordertracker;
            this.NextOrder = null;
            this.NextStatus = ENextOrderStatus.NULL;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets a value indicating whether Acknowledged.
        /// </summary>
        public bool Acknowledged { get; set; }

        /// <summary>
        /// Gets or sets AckStamp.
        /// </summary>
        public DateTime AckStamp { get; set; }

        /// <summary>
        /// Gets a value indicating whether Alive.
        /// </summary>
        public bool Alive
        {
            get
            {
                return this.Sent && !this.Rejected && !this.Cancelled && !this.OutReport && !this.Executed;
            }
        }

        /// <summary>
        /// Gets a value indicating whether Buy.
        /// </summary>
        public bool Buy
        {
            get
            {
                return this.Side == EOrderWay.Buy;
            }
        }

        /// <summary>
        /// Gets or sets CancelAckStamp.
        /// </summary>
        public DateTime CancelAckStamp { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether Cancelled.
        /// </summary>
        public bool Cancelled { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether Cancelling.
        /// </summary>
        public bool Cancelling { get; set; }

        /// <summary>
        /// Gets or sets CancelQuantity.
        /// </summary>
        public int CancelQuantity { get; set; }

        /// <summary>
        /// Gets or sets CancelRejected: Number of rejection to Cancel this order
        /// </summary>
        public int CancelRejected { get; set; }

        /// <summary>
        /// Gets or sets CancelStamp.
        /// </summary>
        public DateTime CancelStamp { get; set; }

        /// <summary>
        /// Gets a value indicating whether Closed.
        /// </summary>
        public bool Closed
        {
            get
            {
                return this.Rejected || this.Cancelled || this.OutReport || this.Executed;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether CorrectionReport.
        /// </summary>
        public bool CorrectionReport { get; set; }

        /// <summary>
        /// Gets or sets CorrectionReportStamp.
        /// </summary>
        public DateTime CorrectionReportStamp { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether Created.
        /// </summary>
        public bool Created { get; set; }

        /// <summary>
        /// Gets or sets CreateStamp.
        /// </summary>
        public DateTime CreateStamp { get; set; }

        /// <summary>
        /// Delta Pending Price = Max(PendingPrice,RequestedPrice)
        /// </summary>
        public double DeltaPendingPrice
        {
            get
            {
                return Math.Max(this.PendingPrice, this.RequestedPrice);
            }
        }

        /// <summary>
        /// Delta Pending quantity = PendingQuantity - RemainingQuantity (signed qty)
        /// </summary>
        public int DeltaPendingQuantity
        {
            get
            {
                return this.PendingQuantity - this.RemainingQuantity;
            }
        }

        /// <summary>
        /// Gets or sets ExecAveragePrice.
        /// </summary>
        public double ExecAveragePrice { get; set; }

        /// <summary>
        /// Gets or sets ExecPrice.
        /// </summary>
        public double ExecPrice { get; set; }

        /// <summary>
        /// Gets or sets ExecQuantity.
        /// </summary>
        public int ExecQuantity { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether Executed.
        /// </summary>
        public bool Executed { get; set; }

        /// <summary>
        /// Gets Executions.
        /// </summary>
        public IExecution[] Executions
        {
            get
            {
                return this.executions.ToArray();
            }
        }

        /// <summary>
        /// Gets or sets LastExecutionStamp.
        /// </summary>
        public DateTime LastExecutionStamp { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether Modified.
        /// </summary>
        public bool Modified { get; set; }

        /// <summary>
        /// Gets or sets ModifyAckStamp.
        /// </summary>
        public DateTime ModifyAckStamp { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether Modifying.
        /// </summary>
        public bool Modifying { get; set; }

        /// <summary>
        /// Gets or sets ModifyRejected: Number of rejection to modify this order
        /// </summary>
        public int ModifyRejected { get; set; }

        /// <summary>
        /// Gets or sets ModifyStamp.
        /// </summary>
        public DateTime ModifyStamp { get; set; }

        /// <summary>
        /// Gets a value indicating whether new order Pending or modifying.
        /// </summary>
        public bool NewPending
        {
            get
            {
                return (this.Sent && !this.Acknowledged && !this.Rejected) || this.Modifying;
            }
        }

        /// <summary>
        /// Gets NextOrder.
        /// </summary>
        public IOrder NextOrder { get; set; }

        /// <summary>
        /// The Next Order Status.
        /// </summary>
        public ENextOrderStatus NextStatus { get; set; }

        /// <summary>
        /// Gets a value indicating whether Open.
        /// </summary>
        public bool Open
        {
            get
            {
                return this.Acknowledged && !this.Rejected && !this.Cancelled && !this.OutReport && !this.Executed;
            }
        }

        /// <summary>
        /// Gets Order.
        /// </summary>
        public IOrder Order { get; private set; }

        /// <summary>
        /// Gets OrderExecQuantity: signed executed quantity
        /// </summary>
        public int OrderExecQuantity
        {
            get
            {
                if (this.Buy)
                {
                    return this.ExecQuantity;
                }
                else if (this.Sell)
                {
                    return -1 * this.ExecQuantity;
                }
                else
                {
                    return 0;
                }
            }
        }

        /// <summary>
        /// Gets OrderRemainingQuantity: signed executed quantity
        /// </summary>
        public int OrderRemainingQuantity
        {
            get
            {
                if (this.Buy)
                {
                    return this.RemainingQuantity;
                }
                else if (this.Sell)
                {
                    return -1 * this.RemainingQuantity;
                }
                else
                {
                    return 0;
                }
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether OutReport.
        /// </summary>
        public bool OutReport { get; set; }

        /// <summary>
        /// Gets or sets OutReportStamp.
        /// </summary>
        public DateTime OutReportStamp { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether PartExecuted.
        /// </summary>
        public bool PartExecuted { get; set; }

        /// <summary>
        /// Gets a value indicating whether Pending.
        /// </summary>
        public bool Pending
        {
            get
            {
                return (this.Sent && !this.Acknowledged && !this.Rejected && !this.Cancelled && !this.OutReport && !this.Executed) || this.Cancelling ||
                       this.Modifying;
            }
        }

        /// <summary>
        /// Pending Price
        /// </summary>
        public double PendingPrice { get; set; }

        /// <summary>
        /// Gets or sets PendingQuantity.
        /// </summary>
        public int PendingQuantity { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether Rejected.
        /// </summary>
        public bool Rejected { get; set; }

        /// <summary>
        /// Gets or sets RejectReason.
        /// </summary>
        public string RejectReason { get; set; }

        /// <summary>
        /// Gets or sets RejectStamp.
        /// </summary>
        public DateTime RejectStamp { get; set; }

        /// <summary>
        /// Gets or sets RemainingQuantity.
        /// </summary>
        public int RemainingQuantity { get; set; }

        /// <summary>
        /// Gets or sets RequestedPrice.
        /// </summary>
        public double RequestedPrice { get; set; }

        /// <summary>
        /// Gets or sets RequestedQuantity.
        /// </summary>
        public int RequestedQuantity { get; set; }

        /// <summary>
        /// Gets a value indicating whether Sell.
        /// </summary>
        public bool Sell
        {
            get
            {
                return this.Side == EOrderWay.Sell;
            }
        }

        /// <summary>
        /// Gets or sets SendStamp.
        /// </summary>
        public DateTime SendStamp { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether Sent.
        /// </summary>
        public bool Sent { get; set; }

        /// <summary>
        /// Gets or sets Side.
        /// </summary>
        public EOrderWay Side { get; set; }

        /// <summary>
        /// Get the status
        /// </summary>
        public string StringStatus
        {
            get
            {
                if (this.Rejected)
                {
                    return "Rejected";
                }
                else if (this.Executed)
                {
                    return "Executed";
                }
                else if (this.Cancelled)
                {
                    return "Cancelled";
                }
                else if (this.Modified)
                {
                    return "Modified";
                }
                else if (this.Acknowledged)
                {
                    return "Acknowledged";
                }
                else
                {
                    return "Pending";
                }
            }
        }

        /// <summary>
        /// Gets Parent.
        /// </summary>
        public IOrderTracker Tracker { get; private set; }

        #endregion

        #region Public Methods

        /// <summary>
        /// The add execution.
        /// </summary>
        /// <param name="exec">
        /// The exec.
        /// </param>
        public void AddExecution(IExecution exec)
        {
            this.executions.Add(exec);
            this.LastExecutionStamp = Timings.Now;
        }

        #endregion
    }
}